﻿using System;
using System.ComponentModel.Composition;
using System.Threading;
using System.Windows.Threading;
using ScrumFactory.Composition.ViewModel;
using ScrumFactory.Composition;

namespace ScrumFactory.Windows {
    

    [Export(typeof(IBackgroundExecutor))]
    public class BackgroundExecutor : IBackgroundExecutor
    {
        private Dispatcher dispatcher;

        [Import(typeof(IEventAggregator))]
        private IEventAggregator EventAggregator { get; set; }

        [Import(typeof(IDialogService))]
        private IDialogService DialogService { get; set; }

        public BackgroundExecutor()
        {
            // This is actually a little tricky, since we know the BackgroundExecutor is created in the UI thread
            // during the Application class bootstrap
            this.dispatcher = Dispatcher.CurrentDispatcher;
        }

        public void StartBackgroundTask<TResult>(Func<TResult> task, Action<TResult> callback) {
            StartBackgroundTask<TResult>(task, callback, null);
        }

        public void StartBackgroundTask<TResult>(Func<TResult> task, Action<TResult> callback, Action<System.Exception> onError) {
            TResult result;

            new Thread(() => {
                try {
                    result = task();                    
                    dispatcher.Invoke(DispatcherPriority.Normal,
                        new Action<TResult>(r => { callback(r); }), result);
                } catch (System.Exception ex) {
                    LocalizeBusinessRuleViolationException(ex, task.Target.GetType());
                    OnErrorDefault(ex);
                    if (onError != null)
                        dispatcher.Invoke(onError, ex);
                }

            }).Start();
        }

        public void StartBackgroundTask(Action task, Action callback) {
            StartBackgroundTask(task, callback, null);
        }

        public void StartBackgroundTask(Action task, Action callback, Action<System.Exception> onError) {
            new Thread(() => {
                try {
                    task();
                    dispatcher.Invoke(callback, DispatcherPriority.Normal);
                } catch (System.Exception ex) {
                    LocalizeBusinessRuleViolationException(ex, task.Target.GetType());                    
                    OnErrorDefault(ex);
                    if (onError != null)
                        dispatcher.Invoke(onError, ex);
                }                
                }).Start();
        }


        public virtual void OnErrorDefault(System.Exception ex) {                        
            dispatcher.Invoke(
                DispatcherPriority.Normal,
                new Action(() => { EventAggregator.Publish<System.Exception>(ScrumFactoryEvent.ShowAlertMessage, ex); }));                            
        }

        protected virtual void LocalizeBusinessRuleViolationException(System.Exception ex, Type type) {
            if (!(ex is Exceptions.BusinessRuleViolationException))
                return;

            System.Reflection.Assembly assembly = System.Reflection.Assembly.GetAssembly(type);
            System.Resources.ResourceManager r = new System.Resources.ResourceManager(assembly.GetName().Name + ".Properties.Resources", assembly);

            string errorMessage = r.GetString(ex.Message + "_errorMessage");
            if (errorMessage == null)
                errorMessage = ex.Message;
            string errorMessageTitle = r.GetString(ex.Message + "_errorMessageTitle");
            if (errorMessageTitle == null)
                errorMessageTitle = "Error";
            ((Exceptions.BusinessRuleViolationException)ex).LocalizedMessage = errorMessage;
            ((Exceptions.BusinessRuleViolationException)ex).LocalizedMessageTitle = errorMessageTitle;
        }

        
    }
}
